/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package grex.fitnessfunctions.Regression;

/**
 *
 * @author RIK
 */

import grex.Environment;
import grex.PredictionContainer;
import grex.genes.Gene;
import java.util.Enumeration;



import grex.Prediction;
import grex.fitnessfunctions.FitnessFunction;


/**
 *
 * @author rik
 */
public class CORR_Fitness extends FitnessFunction{
    public CORR_Fitness(){
        super(FitnessFunction.CORR);
    }
    
    public CORR_Fitness(String name,Double instanceKey) {
        super(name,instanceKey);
    }

    @Override
     protected double calcFinalError(PredictionContainer pc){
        if(model.getNrOfNodes()==1)
            return 100;
        if(pc.values().size()>0)
            return 100*(1-calcPearsonCorrelation(pc));
        else{
            return 100;
        }
     }
    
     public  double calcPearsonCorrelation(PredictionContainer pc){
        Enumeration<double[]> it = pc.keys();        
        int size = pc.values().size();
        double[] instance = it.nextElement();
        Prediction p = pc.get(instance);
        double result = 0;
        double sum_sq_x = 0;
        double sum_sq_y = 0;
        double sum_coproduct = 0;
        
        double mean_x = p.getPrediction();
        double mean_y = getTargetValue(instance); 
        //for(int i=2;it.hasNext();i++,p=it.next()){ 
        int i=1;
        while(it.hasMoreElements()){
            instance = it.nextElement();
            p=pc.get(instance);
            i++;
            double sweep =Double.valueOf(i-1)/i;
            double delta_x = p.getPrediction()-mean_x;
            double delta_y = getTargetValue(instance)-mean_y;
            sum_sq_x += delta_x * delta_x * sweep;
            sum_sq_y += delta_y * delta_y * sweep;
            sum_coproduct += delta_x * delta_y * sweep;
            mean_x += delta_x / i;
            mean_y += delta_y / i;
        }
        double pop_sd_x = (double) Math.sqrt(sum_sq_x/size);
        double pop_sd_y = (double) Math.sqrt(sum_sq_y/size);
        double cov_x_y = sum_coproduct / size;
        result = cov_x_y / (pop_sd_x*pop_sd_y);
        
        if(Double.isInfinite(result) || Double.isNaN(result))
            return 0;
        return result;
    }

    @Override
    protected double calcPredictionError(Prediction prediction, double targetValue) {
       return 0;
    }


}